#include <iostream>

using std::cout;
using std::endl;

//单例模式，一个类只有一个对象
//
//1、有一个全局的指针（静态数据成员）
//通过静态成员函数，把这个指针申请出来
//释放即delete掉这个指针
//2、构造函数和析构函数都是private
//3、注意手动释放堆空间
class Singleton{
public:
    static Singleton *getInstance(){
        //Singleton *pc; 不能放在这，不然每次进来都会定义一个pc
        if(_pInstance==nullptr){//因为pInstance只有一个，在堆上
            _pInstance = new Singleton();
        }
        return _pInstance;
    }

    static void destroy(){
        if(_pInstance){
            delete _pInstance;
            _pInstance=nullptr;
        }
        else{
            cout<<"单例模式不用释放两次"<<endl;
        }
    }

private:
    Singleton(){
        cout<<"单例模式"<<endl;
    //所以只能在类里定义这唯一一个对象，并把它返回出去，还要存活
    }
    
    ~Singleton(){
        cout<<"注意手动释放那个全局指针指向的堆上的单例模式对象"<<endl;
/*        if(_pInstance){
            delete _pInstance;
            _pInstance=nullptr;
            
        }*/
    }

    static Singleton *_pInstance;
    //静态成员函数不能访问非静态成员，所以这里也设为静态成员
};

Singleton * Singleton::_pInstance=getInstance();
//静态成员变量只能在类的外部进行定义和初始化，而不是在类的内部。
//当你在类的外部定义静态成员变量时，可以直接调用类的静态成员函数，
//因为此时编译器已经知道这个静态成员函数属于哪个类，所以不需要使用作用域限定符来指定。

#if 0
Singleton gs1;
Singleton gs2;
static Singleton ss1;
static Singleton ss2;

这样都不是单例模式
#endif


void test(){
    Singleton *ps1=Singleton::getInstance();
    Singleton *ps2=Singleton::getInstance();
    //Singleton *ps3=Singleton::_pInstance;
    //这样也可以，但是_pInstance是private，不要改成public
    
    cout<<ps1<<endl;
    cout<<ps2<<endl;
    //可见他俩是同一个，单例模式完成

    ps1->destroy();
    ps2->destroy();
    //Singleton::destory();

    //delete ps1;
    //delete ps2;
    //直接delete，容易释放两次。如果把destory的逻辑写在析构函数里，则会一直释放
    //此外，delete会调用private的析构函数，报错

    //Singleton s1;//栈上
    //Singleton s2;//栈上
   
    //Singleton *pc = new Singleton(); 堆上也不行
}

int main()
{   
    test();
    return 0;
}

